package com.ccp.dev.workflow.service;


import com.ccp.dev.core.basic.base.BaseService;
import com.ccp.dev.core.basic.util.ContextUtil;
import com.ccp.dev.core.model.MessageModel;
import com.ccp.dev.core.util.BeanUtils;
import com.ccp.dev.core.util.StringUtil;
import com.ccp.dev.form.model.FormData;
import com.ccp.dev.form.model.FormTable;
import com.ccp.dev.form.service.FormTableService;
import com.ccp.dev.system.dao.SysUserDao;
import com.ccp.dev.system.model.SysUser;
import com.ccp.dev.workflow.bpmutil.ServiceUtil;
import com.ccp.dev.workflow.dao.ActDefModelDao;
import com.ccp.dev.workflow.dao.ProcessRunDao;
import com.ccp.dev.workflow.model.*;
import com.ccp.dev.workflow.model.bpm.ProcessCmd;
import com.ccp.dev.workflow.model.bpm.ProcessTask;
import com.ccp.dev.workflow.service.bpm.thread.TaskThreadService;
import com.ccp.dev.workflow.service.jms.MessageProducer;
import net.sf.json.JSONObject;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * @ClassName TaskMessageService
 * @Description:
 * @Author fanyanyan
 * @Date 2019/7/10
 * @Version V1.0
 **/
@Service
public class TaskMessageService extends BaseService<ProcessTask> {

    @Resource
    private ActDefModelDao actDefModelDao;
    @Resource
    private BpmNodeSetService bpmNodeSetService;
    @Resource
    private SysUserDao sysUserDao;
    @Resource
    private TaskUserService taskUserService;
    @Resource
    private ProcessRunDao processRunDao;
    @Resource
    private MessageProducer messageProducer;
    @Resource
    private FormTableService formTableService;
    @Resource
    private FormHandlerService formHandlerService;
    @Resource
    private SysTemplateService sysTemplateService;
    @Resource
    private NodeMsgTemplateService nodeMsgTemplateService;


    /**
     * 发送 站内消息 短信 邮件 通知
     *
     * @param taskList    任务列表
     * @param informTypes 通知方式
     * @param subject     标题
     * @param map         消息模版
     * @param opinion     意见
     * @throws Exception 异常
     */
    @Transactional(rollbackFor = Exception.class)
    public void notify(List<Task> taskList, String informTypes, String subject, Map<String, String> map, String opinion, String parentActDefId) throws Exception {
        // 通知类型为空。
        if (taskList == null) {
            return;
        }

        //遍历任务将用户和任务对应上。
        for (Task task : taskList) {
            String procDefId = task.getProcessDefinitionId();
            String nodeId = task.getTaskDefinitionKey();
            ActDefModel actDefModel = actDefModelDao.getByProcDefId(procDefId);
            BpmNodeSet bpmNodeSet;
            if (StringUtil.isNotEmpty(parentActDefId)) {
                bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId,procDefId,parentActDefId);
                if (BeanUtils.isEmpty(bpmNodeSet)) {
                    bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId,procDefId,null);
                }
            } else {
                bpmNodeSet = bpmNodeSetService.getByProcDefIdNodeIdOrParentProcDefId(nodeId,procDefId,null);
            }
            if (StringUtil.isEmpty(informTypes)) {
                if (StringUtil.isNotEmpty(bpmNodeSet.getInformType())) {
                    informTypes = bpmNodeSet.getInformType();
                } else {
                    informTypes = actDefModel.getInformType();
                }
            }
            if (StringUtil.isEmpty(informTypes)) {
                continue;
            }
            // 执行人
            String userId = task.getAssignee();
            // 存在指定的用户
            if (ServiceUtil.isAssigneeNotEmpty(userId)) {
                SysUser user = sysUserDao.getById(userId);
                sendMsg(task, map, user, informTypes, parentActDefId, bpmNodeSet, subject, opinion);
            }
            // 获取该任务的候选用户列表
            else {
                Set<SysUser> cUIds = taskUserService.getCandidateUsers(task.getId());
                for (SysUser user : cUIds) {
                    sendMsg(task, map, user, informTypes, parentActDefId, bpmNodeSet, subject, opinion);
                }
            }
        }

    }

    /**
     *
     * @param task  任务
     * @param map   消息模板
     * @param user  用户
     * @param informTypes   消息类型
     * @param parentActDefId    父流程定义id
     * @param bpmNodeSet    节点设置
     * @param subject   标题
     * @param opinion   意见
     * @throws Exception    异常
     */
    private void sendMsg(Task task, Map<String, String> map, SysUser user, String informTypes, String parentActDefId, BpmNodeSet bpmNodeSet, String subject, String opinion) throws Exception {
        SysUser curUser = (SysUser) ContextUtil.getCurrentUser();
        // 是否为代理任务(代理任务发送消息给任务所属人)
        boolean isAgentTask = TaskOpinion.STATUS_AGENT.toString().equals(task.getDescription());
        if (BeanUtils.isEmpty(map)) {
            if (isAgentTask) {
                map = sysTemplateService.getTempByFun(SysTemplate.USE_TYPE_NOTIFYOWNER_AGENT);
            } else {
                map = sysTemplateService.getDefaultTemp();
            }
        }
        if (isAgentTask) {
            user = sysUserDao.getById(task.getOwner());
        }
        // informTypes形如逗号分割字符串：1,2,3
        String[] infoTypeArray = informTypes.split(",");

        //nodeMsgTemplate处理
        ProcessCmd processCmd = TaskThreadService.getProcessCmd();
        FormData formData;
        if (processCmd != null) {
            formData = (FormData) processCmd.getTransientVar("formData");
        } else {
            //没有就自己拼装一个，在追回的时候是没有processCmd对象的，只在启动和next有
            String instanceId = task.getProcessInstanceId();
            ProcessRun processRun = processRunDao.getByProcInstanceId(instanceId);
            if(bpmNodeSet.getFormType()==0) {
                //在线表单获取表单数据
                FormTable formTable = formTableService.getByProcDefId(processRun.getProcDefId());
                formData = formHandlerService.getByKey(formTable.getTableId(), processRun.getBusinessKey(), false);
            }else{
                //TODO URL表单获取表单数据
                formData = formHandlerService.getUrlForm(null,processRun,null,null);
            }
        }
        ActDefModel parentActDelModel = actDefModelDao.getByProcDefId(parentActDefId);
        String parentDef = parentActDelModel == null ? null : parentActDelModel.getProcDefId();
        JSONObject jsonObject = nodeMsgTemplateService.parse(bpmNodeSet.getNodeId(), bpmNodeSet.getProcDefId(), parentDef, formData);
        map.put("htmlDefForm", jsonObject.getString("html"));
        map.put("textDefForm", jsonObject.getString("text"));

        for (String infoType : infoTypeArray) {
            // 循环,找到具体的实现类
            MessageModel messageModel = new MessageModel(infoType);
            messageModel.setReceiveUser(user);
            messageModel.setSubject(subject);
            messageModel.setSendUser(curUser);
            messageModel.setTemplateMap(map);
            messageModel.setExtId(task.getId());
            messageModel.setIsTask(true);
            messageModel.setOpinion(opinion);
            messageProducer.send(messageModel);
        }

        //开始处理是否发信息给启动人
        if (bpmNodeSet.getSendMsgToCreator() == 0) {
            return;
        }
        ProcessRun processRun = null;
        if (processCmd != null) {
            processRun = processCmd.getProcessRun();
        }
        if (processRun == null) {
            //在启动流程时可能获取不了这个，逻辑上也不需要发送
            return;
        }
        SysUser creator = sysUserDao.getById(processRun.getCreatorId());
        //获取模板
        map = sysTemplateService.getTempByFun(SysTemplate.USE_TYPE_SENDTOCREATOR);
        //nodeMsgTemplate处理
        map.put("htmlDefForm", jsonObject.getString("html"));
        map.put("textDefForm", jsonObject.getString("text"));
        for (String infoType : infoTypeArray) {
            // 循环,找到具体的实现类
            MessageModel messageModel = new MessageModel(infoType);
            messageModel.setReceiveUser(creator);
            messageModel.setSendUser(curUser);
            messageModel.setSubject(subject);
            messageModel.setTemplateMap(map);
            messageModel.setExtId(task.getId());
            messageModel.setIsTask(true);
            messageModel.setOpinion(opinion);
            messageProducer.send(messageModel);
        }
    }

    /**
     * 发送消息接口
     *
     * @param sendUser
     *            发送者名称
     * @param receiverUserList
     *            接收者用户列表
     * @param informTypes
     *            发送消息类型
     * @param msgTempMap
     *            消息模板
     * @param subject
     *            事项名称
     * @param opinion
     *            意见或原因
     * @param taskId
     *            任务Id
     * @param runId
     *            流程运行ID
     * @param userCopyIdMap
     *            流程转发抄送时对应的用户抄送Id Map
     */
    public void sendMessage(SysUser sendUser, List<SysUser> receiverUserList, String informTypes, Map<String, String> msgTempMap, String subject, String opinion, String taskId, String runId, Map<String, String> userCopyIdMap){
        if (StringUtil.isEmpty(informTypes)) {
            return;
        }
        if (BeanUtils.isEmpty(sendUser)) {
            sendUser = new SysUser();
            sendUser.setUserId("0");
            sendUser.setFullName("系统消息");
        }
        if (BeanUtils.isEmpty(receiverUserList)) {
            return;
        }
        if (BeanUtils.isEmpty(msgTempMap)) {
            return;
        }

        boolean isTask;
        String extId;
        if (BeanUtils.isNotIncZeroEmpty(taskId)) {
            isTask = true;
            extId = taskId;
        } else {
            isTask = false;
            extId = runId;
        }
        for (SysUser receiverUser : receiverUserList) {
            // informTypes形如逗号分割字符串：1,2,3
            String[] infoTypeArray = informTypes.split(",");
            for (String infoType : infoTypeArray) {
                // infoType一定要指定，其值与handlersMap 中的key对应：1邮件，2短信，3内部消息
                MessageModel messageModel = new MessageModel(infoType);
                messageModel.setReceiveUser(receiverUser);
                messageModel.setSendUser(sendUser);
                messageModel.setSubject(subject);
                messageModel.setTemplateMap(msgTempMap);
                messageModel.setExtId(extId);
                messageModel.setIsTask(isTask);
                messageModel.setOpinion(opinion);
                messageModel.setSendDate(new Date());
                // TODO 2020.03.11 注释逻辑：此处影响（我的办结）转发流程发送消息的消息类型处理 ↓
                //  对应影响方法 MessageProducer.getMessageType（）的if判断——由于messageModel的vars存在copyId键值对，导致消息类型无法正常获取
                // 转发抄送以内部消息发送时，把抄送转发的ID传过去，作为生成超链接时的URL
//                if (BeanUtils.isNotEmpty(userCopyIdMap)) {
//                    Map<String, String> varMap = new HashMap<>(2);
//                    varMap.put("copyId", userCopyIdMap.get(receiverUser.getUserId()));
//                    messageModel.setVars(varMap);
//                }
                messageProducer.send(messageModel);
            }
        }
    }

    /**
     * 直接发送消息
     *
     * @param sendUser
     *            发送者
     * @param receiverUserList
     *            接受者
     * @param informTypes
     *            消息方式
     * @param title
     *            标题
     * @param content
     *            内容
     */
    public void sendMessage(SysUser sendUser, List<SysUser> receiverUserList, String informTypes, String title, String content) {
        for (SysUser receiverUser : receiverUserList) {
            // informTypes形如逗号分割字符串：1,2,3
            String[] infoTypeArray = informTypes.split(",");
            for (String infoType : infoTypeArray) {
                // 循环,找到具体的实现类
                MessageModel messageModel = new MessageModel(infoType);
                messageModel.setReceiveUser(receiverUser);
                messageModel.setSendUser(sendUser);
                messageModel.setSubject(title);
                messageModel.setSendDate(new Date());
                messageModel.setContent(content);
                messageProducer.send(messageModel);
            }

        }
    }
}
